#include <vector>
#include <string>
#include <iostream>
#include "udp.h"

namespace Platinum{
		namespace Net{
								
				/**
				*  MakeSocket creates a UDP socket and returns the file pointer to that socket, note: the socket file pointer is an INT
				*/
				SOCKET MakeSocket(){return(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));}
				
				namespace UDP{
						
					/**
					*	The Listener Class is literally an ear to the ground class intended for listening for incoming data
					*	It is the Listen side of a client or server object.
					*/
					Listener::Listener(int port) : iPort(port)
					{
						if ((iSock = MakeSocket()) == INVALID_SOCKET) {exit(1);}

						MyAddr.sin_family = AF_INET;         // host byte order
						MyAddr.sin_port = htons(iPort);     // short, network byte order
						MyAddr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
						memset(MyAddr.sin_zero, '\0', sizeof MyAddr.sin_zero);
						if (bind(iSock, (struct sockaddr *)&MyAddr, sizeof MyAddr) == -1) {exit(1);}
						#ifdef DEBUG
							std::cout << "Listener Bound to port " << iPort << std::endl;
						#endif

					}//End of Constructor
								
					Listener::~Listener()
					{
						closesocket(iSock);
					}//End of Destructor
								
					/**
					*	Listen causes the Listener to block until data is recieved, 
					*	Listen returns a pointer to a Packet struct which has IP and Data members both are type string
					*	Ideally Listen should be called in a loop in a seperate thread, if you need to do anything else while waiting for Data
					*	Make sure to delete the packet returned when your are finished with it!
					*/
					Packet* Listener::Listen()
					{
						Packet* pMyPacket = new Packet;
						AddrLen = sizeof TheirAddr;
						memset(sBuf,'\0',MAXBUF); //Re-Initialize Buffer
						
						#ifdef DEBUG
							std::cout << "Listener Waiting On Packet." << std::endl; 
						#endif
						
						//This statement blocks until data is recieved at which time execution will resume.									
						
						//recvfrom(iSock, sBuf, MAXBUF-1, 0,(SOCKADDR *)&TheirAddr, &AddrLen);
						if ((iNumBytes = recvfrom(iSock, sBuf, MAXBUF-1 , 0,(SOCKADDR *)&TheirAddr, &AddrLen)) == -1)
						{
								pMyPacket->IP = "";
								pMyPacket->Data = "";
						}
												
						pMyPacket->IP = inet_ntoa(TheirAddr.sin_addr);
						pMyPacket->Data = sBuf;
						#ifdef DEBUG
							std::cout << "Packet Recieved From: " << pMyPacket->IP << std::endl;
							std::cout << "Packet Contains: " << pMyPacket->Data << std::endl;
						#endif
						
						return(pMyPacket);
					}
								
						
					/**
					*	The Sender Class is used for sending data out over UDP
					*	It is the send side of a persistant client object
					*/
					int Sender::SendAll(char *buf, int len)
					{
						int total = 0;        /// how many bytes we've sent
						int bytesleft = len; /// how many we have left to send
						int n  = -1;

						while(total < len) {
							n = sendto(iSock, buf+total, bytesleft, 0, (struct sockaddr *)&Dest, sizeof Dest);
							if (n == -1) { break; }
							total += n;
							bytesleft -= n;
						}
						delete(buf);
						return n==-1?-1:0; // return -1 on failure, 0 on success
					}
								
					Sender::Sender(std::string ip,int port, int sock) : IP(ip),iPort(port), iSock(sock)
					{
						iPort = port;
						// build destination
						Dest.sin_family = AF_INET;
						//inet_aton(IP.c_str(), &Dest.sin_addr);
						Dest.sin_addr.s_addr = inet_addr(IP.c_str());

						Dest.sin_port = htons(iPort);
						#ifdef DEBUG
							std::cout << "Sender Created for " << IP << ":" << iPort << std::endl;
						#endif

					}

					Sender::~Sender()
					{
						closesocket(iSock);
					}
								
					int Sender::Send(std::string Data)
					{
						#ifdef DEBUG
							std::cout << "Sender Sending: " << Data << " to " << IP << ":" << iPort << std::endl;
						#endif
						return(SendAll(strtocharp(Data),Data.length()));
					}
				}
		}
}
